package com.meida.module.pay.provider.service.impl;

import com.meida.common.enums.AccountTypeEnum;
import com.meida.common.base.service.BaseAppAccountService;
import com.meida.common.mybatis.base.service.impl.BaseServiceImpl;
import com.meida.common.base.entity.EntityMap;
import com.meida.common.mybatis.model.ResultBody;
import com.meida.common.mybatis.query.CriteriaQuery;
import com.meida.common.security.OpenHelper;
import com.meida.common.utils.ApiAssert;
import com.meida.common.base.utils.FlymeUtils;
import com.meida.module.pay.client.entity.PayBalance;
import com.meida.module.pay.client.entity.PayBalanceLog;
import com.meida.module.pay.provider.mapper.PayBalanceMapper;
import com.meida.module.pay.provider.service.PayBalanceLogService;
import com.meida.module.pay.provider.service.PayBalanceService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;

/**
 * 余额表 实现类
 *
 * @author flyme
 * @date 2019-12-16
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class PayBalanceServiceImpl extends BaseServiceImpl<PayBalanceMapper, PayBalance> implements PayBalanceService {

    @Resource
    private PayBalanceLogService payBalanceLogService;

    @Autowired(required = false)
    private BaseAppAccountService baseAppAccountService;

    @Override
    public ResultBody beforePageList(CriteriaQuery<PayBalance> cq, PayBalance balance, EntityMap requestMap) {
        cq.select("user.userName", "user.nickName", "user.mobile");
        cq.select(PayBalance.class, "*");
        cq.eq("user.userName", requestMap.get("userName"));
        cq.eq("user.mobile", requestMap.get("mobile"));
        cq.createJoinAppUser();
        return super.basePageList(cq);
    }

    @Override
    public PayBalance getByUserIdAndUserType(Long userId, String userType) {
        CriteriaQuery<PayBalance> cq = new CriteriaQuery(PayBalance.class);
        PayBalance balance = getOne(cq.eq("userId", userId).eq("userType", userType));
        //如果用户的余额为空，重新插入余额。
        if (FlymeUtils.isEmpty(balance)) {
            PayBalance payBalance1 = new PayBalance();
            payBalance1.setUserId(userId).setUserType(userType).setAmount(new BigDecimal(0)).setVersion(new Long(1));
            payBalance1.insert();
            balance = payBalance1;
        }
        return balance;
    }

    @Override
    public boolean addBalance(Long userId, String userType, BigDecimal amount, String outTradeNo, Integer type, Long busId, String title, String body) {
        PayBalance balance = getByUserIdAndUserType(userId, userType);
        balance.setAmount(balance.getAmount().add(amount));
        boolean update = balance.updateById();
        //余额变动有乐观锁，高并发的时候会更新失败。
        if (update) {
            PayBalanceLog balanceLog = new PayBalanceLog();
            balanceLog.setUserId(userId).setUserType(userType).setBalanceId(balance.getBalanceId()).setAmount(amount).setTradeNo(outTradeNo).setType(type).setBusId(busId).setTitle(title).setBody(body);
            balanceLog.insert();
        }
        return update;
    }

    @Override
    public boolean subtractBalance(Long userId, String userType, BigDecimal amount, String outTradeNo, Integer type, Long busId, String title, String body, Integer status, String payPwd) {
        PayBalance balance = getByUserIdAndUserType(userId, userType);
        String payPwdByDataBase = balance.getPaypwd();
        ApiAssert.isNotEmpty("请先设置支付密码", payPwdByDataBase);
        ApiAssert.eq("支付密码不正确", payPwd, payPwdByDataBase);
        //账户余额
        BigDecimal balanceAmount = FlymeUtils.getBigDecimal(balance.getAmount(), "0");
        //绑定金余额
        BigDecimal bindAmount = FlymeUtils.getBigDecimal(balance.getBindAmount(), "0");
        BigDecimal totalAmount = balanceAmount.add(bindAmount);
        if (totalAmount.compareTo(amount) == -1) {
            ApiAssert.failure("余额不足");
        }
        if (FlymeUtils.gtzero(bindAmount)) {
            //绑定金够支付的情况
            if (FlymeUtils.ge(bindAmount, amount)) {
                balance.setBindAmount(bindAmount.subtract(amount));
            }
            //绑定金不够支付的情况
            if (FlymeUtils.lt(bindAmount, amount)) {
                BigDecimal surplusAmount = amount.subtract(bindAmount);
                balance.setBindAmount(new BigDecimal("0"));
                balance.setAmount(balanceAmount.subtract(surplusAmount));
            }
        } else {
            balance.setAmount(balanceAmount.subtract(amount));
        }

        boolean update = balance.updateById();
        //余额变动有乐观锁，高并发的时候会更新失败。
        if (update) {
            PayBalanceLog balanceLog = new PayBalanceLog();
            balanceLog.setUserId(userId).
                    setUserType(userType).
                    setBalanceId(balance.getBalanceId()).
                    setAmount(new BigDecimal("-" + amount)).
                    setTradeNo(outTradeNo).
                    setType(type).
                    setBusId(busId).
                    setTitle(title).
                    setBody(body).
                    setStatus(status);
            balanceLog.insert();
        }
        return update;
    }


    @Override
    public PayBalance addUserBalance(Long userId) {
        PayBalance balance = getByUserId(userId);
        if (FlymeUtils.isEmpty(balance)) {
            balance = new PayBalance();
            balance.setUserId(userId);
            balance.setBalanceId(userId);
            balance.setVersion(100L);
            balance.setCompanyId(OpenHelper.getCompanyId());
            balance.setAmount(new BigDecimal("0"));
            balance.setBindAmount(new BigDecimal("0"));
            save(balance);
        }
        return balance;
    }

    @Override
    public ResultBody setPayPwd(String payPwd, String smsCode) {
        Long userId = OpenHelper.getUserId();
        if (FlymeUtils.isNotEmpty(baseAppAccountService)) {
            EntityMap entityMap = baseAppAccountService.getAppAccount(userId, AccountTypeEnum.MOBILE.getCode());
            String account = entityMap.get("account");
            //校验验证码
            redisUtils.validSmsCode(account, smsCode);
        }
        // String encodePassword = passwordEncoder.encode(paypwd);
        PayBalance balance = addUserBalance(userId);
        balance.setPaypwd(payPwd);
        updateById(balance);
        return ResultBody.msg("设置成功");
    }


    @Override
    public PayBalance getByUserId(Long userId) {
        return getByProperty("userId", userId);
    }

    @Override
    public Boolean addBindAmount(Long userId, Long sourceUserId, BigDecimal amount) {
        PayBalance balance = getByUserId(userId);
        if (FlymeUtils.isEmpty(balance)) {
            //当推荐人账户不存在时创建账户
            balance = new PayBalance();
            balance.setUserId(userId);
            balance.setBindAmount(amount);
            balance.setVersion(100L);
            balance.setAmount(new BigDecimal("0"));
            save(balance);
        } else {
            BigDecimal bindAmount = balance.getBindAmount();
            balance.setBindAmount(bindAmount.add(amount));
            updateById(balance);
        }
        return payBalanceLogService.addBalanceLog(balance.getBalanceId(), userId, amount, "邀请奖励", "收益", 1, sourceUserId);
    }
}
